package com.ly.gen.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ly.common.core.bean.R;
import com.ly.common.core.bean.vo.TreeVO;
import com.ly.common.core.config.properties.GenProperties;
import com.ly.common.core.exception.ServiceException;
import com.ly.common.core.utils.BaseUtils;
import com.ly.gen.dto.GenCodeDTO;
import com.ly.gen.dto.GenFilePathDTO;
import com.ly.gen.entity.GenDataTable;
import com.ly.gen.entity.GenField;
import com.ly.gen.entity.GenTable;
import com.ly.gen.service.IGenFieldService;
import com.ly.gen.service.IGenService;
import com.ly.gen.service.IGenTableService;
import com.ly.gen.utils.GenDbUtils;
import com.ly.gen.utils.GenUtils;
import com.ly.system.util.TreeUtils;
import freemarker.template.Configuration;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 代码生成-impl
 *
 * @author luoyun
 * @Date: 2025/6/12 20:26
 * @Note:
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class GenServiceImpl implements IGenService {

    private final IGenTableService tableService;
    private final IGenFieldService fieldService;
    private final GenProperties genProperties;

    @Override
    public R getTablePage(GenTable entity, Page<GenTable> page) {
        IPage<GenTable> pageList = tableService.page(
                page,
                new LambdaQueryWrapper<GenTable>()
                        .like(StrUtil.isNotEmpty(entity.getTableName()), GenTable::getTableName, entity.getTableName())
                        .orderByDesc(GenTable::getCreateTime)
        );
        return R.ok(pageList);
    }

    @Override
    public R getTableList(String tableName) {
        List<GenDataTable> allTable = GenDbUtils.getAllTable();
        List<String> allList = allTable.stream()
                .map(n -> n.getTableName()).collect(Collectors.toList());
        // 已存在的
        List<GenTable> existTable = tableService.list();
        List<String> existList = existTable.stream().map(n -> n.getTableName()).collect(Collectors.toList());
        // 排除已经生成的
        allList.removeAll(existList);
        if (StrUtil.isNotEmpty(tableName)) {
            allList = allList.stream().filter(n -> n.indexOf(tableName) != -1).collect(Collectors.toList());
        }
        List<HashMap> list = new ArrayList<>();
        allList.stream()
                .forEach(n -> {
                    HashMap map = new HashMap();
                    map.put("tableName", n);
                    list.add(map);
                });
        return R.ok(list);
    }

    @Override
    public R addTables(String tableNames) {
        if (StrUtil.isEmpty(tableNames)) {
            return R.fail("未识别的表名信息");
        }
        List<String> tabList = StrUtil.split(tableNames, ",");
        tabList.stream().forEach(n -> tableService.addByTableName(n));
        return R.ok("全部导入完成！");
    }

    @Override
    public R delete(String id) {
        boolean flag = tableService.removeById(id);
        fieldService.remove(
                new LambdaQueryWrapper<GenField>()
                        .in(GenField::getCgformHeadId, id)
        );
        return flag ? R.ok(true, "删除成功") : R.fail("删除失败");
    }

    @Override
    public R getTableInfo(String id) {
        GenTable entity = tableService.getById(id);
        if (entity == null) {
            return R.fail("未找到对应实体");
        }
        HashMap map = new HashMap(5);
        map.put("main", entity);
        Integer tableType = entity.getTableType();
        if ("Y".equals(entity.getIsTree())) {
            tableType = 3;
        }
        List<Map<String, Object>> jspModelList = new ArrayList<>();
        Map<String, Object> jspMap = Map.of(
                "label", "经典风格", "value", "one"
        );
        jspModelList.add(jspMap);
        map.put("jspModeList", jspModelList);
        // ly：获取文件生成路径
        map.put("projectPath", genProperties.getProjectPath());
        return R.ok(map);
    }

    @Override
    public R getCode(GenCodeDTO dto) {
        dto.setTemplatePath("gen/code-template-online");
        dto.setStylePath("default.one");
        dto.setBussiPackage(genProperties.getBussiPackage());
        String tabId = dto.getId();
        GenTable table = tableService.getById(tabId);
        List<GenField> fieldList = fieldService.list(
                new LambdaQueryWrapper<GenField>()
                        .eq(GenField::getCgformHeadId, tabId)
                        .orderByAsc(GenField::getOrderNum)
        );
        if (table == null || CollUtil.isEmpty(fieldList)) {
            return R.fail("数据库表异常，请重新导入再生成");
        }
        table.setEntityPackage(dto.getEntityPackage());
        table.setBussiPackage(genProperties.getBussiPackage());
        // 模版参数设置
        String paramsJson = JSON.toJSONString(dto);
        Map<String, Object> paramsMap = JSONObject.parseObject(paramsJson, Map.class);
        // 参数设置 step1：设置表基础信息  步骤1
        paramsMap.put("tableVo",
                Map.of(
                        "tableTxt", StrUtil.isNotEmpty(table.getTableTxt()) ? table.getTableTxt() : table.getTableName(),
                        "fieldRowNum", 1
                ));
        // 参数设置 step2：设置主键
        paramsMap.put("primaryKeyField", "id");
        // 参数设置 step3：设置列信息
        paramsMap.put("fieldVo", fieldList);
        paramsMap.put("currentDate", DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN));
        // 获取子目录下全部文件夹，用于生成2个Configuration 1：common 2：default
        File[] fileList = FileUtil.ls(dto.getTemplatePath());
        Configuration configuration = GenUtils.getConfiguration(fileList);
        // 模版的父目录
        String path = "gen/code-template-online/default";
        List<File> files = FileUtil.loopFiles(path,file -> !file.getName().endsWith(".7z"));
        List<String> codeFileList = new ArrayList<>();
        JSONObject jsonObject = new JSONObject();
        for (File file : files) {
            String getFile = GenUtils.getFreemarkerFile(file, table, genProperties, paramsMap, configuration);
            // System.out.println("原始路径" + file.getPath());
            // System.out.println("本地路径" + getFile);
            jsonObject.put(file.getPath(), getFile);
            codeFileList.add(getFile);
        }
        table.setExtConfigJson(jsonObject.toJSONString());
        tableService.updateById(table);
        log.info("最终生成的文件路径：{}", codeFileList);
        return R.ok(codeFileList);
    }

    @Override
    public void getCodeView(String path) {
        try {
            path = URLDecoder.decode(path, "UTF-8");
        } catch (Exception e) {
            throw new ServiceException("文件路径解析失败：不合法");
        }
        File file = new File(path);
        boolean exist = file.exists();
        if (!exist) {
            throw new ServiceException("文件路径解析失败：文件不存在");
        }
        String fileName = StrUtil.subAfter(path, "/", true);
        HttpServletResponse response = BaseUtils.getResponse();
        response.setContentType("application/force-download");
        response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 强制下载
        response.setHeader("Content-Length", String.valueOf(FileUtil.size(file))); // 文件大小
        InputStream inputStream = FileUtil.getInputStream(path);
        try {
            ServletOutputStream outputStream = response.getOutputStream();
            byte[] buffer = new byte[8192]; // 8KB 缓冲区
            int bytesRead;
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                outputStream.write(buffer, 0, bytesRead);
            }
            outputStream.flush();
        } catch (Exception e) {
        }
    }

    @Override
    public R getCodeViewFilePathTree(GenFilePathDTO dto) {
        GenTable table = tableService.getById(dto.getTableId());
        // 封装公共父级
        TreeVO root = new TreeVO("gen", "gen", null, false);
        List<TreeVO> rootVOS = Arrays.asList(new TreeVO[]{root});
        // 模版的父目录
        String path = "gen/code-template-online/default/java/${bussiPackage}/${entityPackage}";
        List<TreeVO> treeVOS = TreeUtils.buildTreeFromFolder(path, table);
        root.setChildren(treeVOS);
        return R.ok(rootVOS);
    }

    @Override
    public R getCodeViewText(String path) {
        String fileText = FileUtil.readUtf8String(path);
        return R.ok(fileText);
    }
}
